/*
 * This file is part of quickReminder, a software for gamers
 *
 * Copyright (C) 2006-2008 Lucas Romero
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using System.Text.RegularExpressions;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using ListViewSorter;
using ManagedWinapi.Accessibility;
using ManagedWinapi.Windows;
using LucasCode.Win32;
using LucasCode;
using System.Diagnostics;
using System.Threading;
using System.Data.SQLite;
using System.Runtime.InteropServices;

namespace quickReminder
{
    public partial class AequitasChecker : Form
    {
        ListViewItem CurrentResult = null;

        ListViewColumnSorter sort = new ListViewColumnSorter();
        bool CancelCheck = false;
        KeyValueCollection settings = new KeyValueCollection();
        FormConfigViewer configviewer = new FormConfigViewer();
        string config = string.Empty;
        public AequitasChecker()
        {
            InitializeComponent();
            cbAutoCheckWithAequitas.Checked = Properties.Settings.Default.InspectorAutoCheckForManipulation;
            cbOnlyShowAnomalies.Checked = Properties.Settings.Default.InspectorOnlyAnomalies;
        }

        private void AequitasChecker_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        private string getConfigFromAeq(string file)
        {
            ZipInputStream s = null;
            ZipEntry theEntry;
            string text = string.Empty;
            try
            {
                s = new ZipInputStream(File.OpenRead(file));
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    if (!theEntry.Name.StartsWith("CONFIG_"))
                        continue;
                    StreamReader r = new StreamReader(s);
                    text = r.ReadToEnd();
                    r.Close();
                    break;
                }
            }
            catch { return String.Empty; }
            finally
            {
                if (s != null)
                    s.Close();
            }
            return text;
        }

        private string getLogFromAeq(string file)
        {
            ZipInputStream s = null;
            ZipEntry theEntry;
            string text = string.Empty;
            try
            {
                s = new ZipInputStream(File.OpenRead(file));
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    if (!theEntry.Name.StartsWith("LOG_"))
                        continue;
                    StreamReader r = new StreamReader(s);
                    text = r.ReadToEnd();
                    r.Close();
                    break;
                }
            }
            catch { return String.Empty; }
            finally
            {
                if (s != null)
                    s.Close();
            }
            return text;
        }

        private int GetLineFromIndex(string text, int index, int startindex)
        {
            if (text.Length <= index)
                return -1;
            int line = 0;
            for (int i = startindex; i <= index; i++)
                if (text[i] == '\n')
                    line++;
            return line;
        }

        private int GetLineFromIndex(string text, int index)
        {
            if(text.Length <= index)
                return -1;
            int line = 1;
            for (int i = 0; i <= index;i++ )
                    if (text[i] == '\n')
                        line++;
            return line;
        }

        private void CheckConfigs(string content, bool duplicate, bool ignorevalvedir)
        {
            config = content;
            AddFormattedString("Starting config check ...");
            settings.Clear();
            DateTime start = DateTime.Now;

            StatusProgress.Maximum = GetLineFromIndex(content, content.Length - 1);
            StatusProgress.Value = 0;
            string ConfigRegex = @"\[{STEAM}\\steamapps\\{STEAMACCOUNT}\\(.*?)\]\s(.*?)\s\[/{STEAM}\\steamapps\\{STEAMACCOUNT}\\\1\]";
            foreach (Match m in Regex.Matches(content, ConfigRegex, RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled))
            {
                AddFormattedString("Checking " + m.Groups[1].Value);
                int confline = GetLineFromIndex(content, m.Groups[2].Index);
                CheckConfigExpression(m.Groups[2].Value, m.Groups[1].Value, confline, null);
            }
            TimeSpan dur = DateTime.Now - start;
            lWrongSettings.Text = settings.WrongSettings.ToString();
            if (settings.WrongSettings > 0)
                lWrongSettings.ForeColor = Color.Red;
            else
                lWrongSettings.ForeColor = SystemColors.WindowText;
            lSuspiciousScripts.Text = settings.SuspiciousScripts.ToString();
            if (settings.SuspiciousScripts > 0)
                lSuspiciousScripts.ForeColor = Color.Red;
            else
                lSuspiciousScripts.ForeColor = SystemColors.WindowText;

            AddFormattedString(String.Format("Config check complete after {0:t}. Scanned {4} line(s) ({1:f2} lines/second).\nFound {2} illegal setting(s) and {3} suspicios script(s)",
                dur, StatusProgress.Maximum / dur.TotalSeconds, settings.WrongSettings, settings.SuspiciousScripts, StatusProgress.Maximum));
            StatusText.Text = String.Format("Scanned {0} line(s). Found {1} illegal setting(s) and {2} suspicios script(s)", StatusProgress.Maximum, settings.WrongSettings, settings.SuspiciousScripts);
            StatusProgress.Value = StatusProgress.Maximum;
        }

        private void CheckScreenshots(string logcont, string aeqfile)
        {
            ScreenshotInfoCollection logscreens = new ScreenshotInfoCollection();
            ScreenshotInfoCollection zipscreens = new ScreenshotInfoCollection();

            string ScreenshotRegex = @"^(\d+\.\d+\.\d{4} \d+:\d+:\d+) - Screenshot -> ([a-zA-Z0-9\-+]*?=\.jpg) \(Timing: (\d+)\)";
            foreach(Match m in Regex.Matches(logcont,ScreenshotRegex,RegexOptions.Multiline | RegexOptions.IgnoreCase))
            {
                DateTime WriteTime = DateTime.Parse(m.Groups[1].Value);
                logscreens.Add(new ScreenshotInfo(m.Groups[2].Value, WriteTime));
                //log.Text += String.Format("Screenshot: {0} created @ {1}", m.Groups[3].Value, WriteTime) + Environment.NewLine;
            }

            string BmpScreenshotRegex = @"^(\d+\.\d+\.\d{4} \d+:\d+:\d+) - Bitmap has been converted: [a-zA-Z0-9\-+]*?=\.bmp > ([a-zA-Z0-9\-+]*?=\.jpg)";
            foreach (Match m in Regex.Matches(logcont, BmpScreenshotRegex, RegexOptions.Multiline | RegexOptions.IgnoreCase))
            {
                DateTime WriteTime = DateTime.Parse(m.Groups[1].Value);
                logscreens.Add(new ScreenshotInfo(m.Groups[2].Value, WriteTime));
                //log.Text += String.Format("Screenshot: {0} created @ {1}", m.Groups[3].Value, WriteTime) + Environment.NewLine;
            }

            string CustomFileRegex = @"^(\d+\.\d+\.\d{4} \d+:\d+:\d+) - Found custom file: (.*?) - saving it as: (.*?) - MD5: (.*?) - (.*?)\r*$";
            foreach (Match m in Regex.Matches(logcont, CustomFileRegex, RegexOptions.Multiline | RegexOptions.IgnoreCase))
            {
                AddFormattedString(String.Format("WARNING!\tCustomfile found: '{0}'", m.Groups[2].Value), Color.Red, false);
            }


            ZipInputStream s = null;
            ZipEntry theEntry;
            string text = string.Empty;
            try
            {
                s = new ZipInputStream(File.OpenRead(aeqfile));
                while ((theEntry = s.GetNextEntry()) != null)
                {
                    if (!theEntry.Name.ToLower().EndsWith(".jpg"))
                        continue;
                    zipscreens.Add(new ScreenshotInfo(Path.GetFileName(theEntry.Name),theEntry.DateTime));
                }
            }
            catch {}
            finally
            {
                if (s != null)
                    s.Close();
            }

            if(logscreens.Count != zipscreens.Count)
            {
                AddFormattedString(String.Format("WARNING!\tThere should be {0} screenshots, but there are {1}", logscreens.Count, zipscreens.Count), Color.Red, false);
            }
            foreach(ScreenshotInfo i in logscreens)
            {
                ScreenshotInfo zipscreen = zipscreens[i.Name];
                if (zipscreen != null)
                {
                    if(zipscreen.LastWriteDate.Subtract(i.LastWriteDate).Duration() > new TimeSpan(0,0,2))
                        AddFormattedString(String.Format("WARNING!\t{0} was probably altered (LastWriteDate mismatch! Last written {1} after creation)!", i.Name, zipscreen.LastWriteDate - i.LastWriteDate), Color.Red, false);
                }
                else
                {
                    AddFormattedString(String.Format("WARNING!\t{0} missing in aequitasfile!", i.Name), Color.Red, false);
                }
            }
        }

        private void PerformAequitasCheck(string aeqfile)
        {
            CurrentResult = lw.TopItem;
            log.Clear();
            //lw.Items.Clear();
            string logcont = getLogFromAeq(aeqfile);
            string UserRegex = @"\d+\.\d+\.\d{4} \d+:\d+:\d+ - Received Player Info: (.+?) \(ID: (\d+)\)";

            string MatchlinkRegex = @"^\d+\.\d+\.\d{4} \d+:\d+:\d+ - Started Monitoring - Matchlink: (.*?)\r*$";
            string ColorDepthRegex = @"^\d+\.\d+\.\d{4} \d+:\d+:\d+ - Color Depth Settings: (\d+)bpp";




            Match m = Regex.Match(logcont, UserRegex);
            log.AppendText(String.Format("Nickname: {0}, ID: {1}", m.Groups[1].Value, m.Groups[2].Value) + Environment.NewLine);

            m = Regex.Match(logcont, ColorDepthRegex, RegexOptions.Multiline);
            log.AppendText(String.Format("Color Depth: {0}", m.Groups[1].Value) + Environment.NewLine);
            if(m.Groups[1].Value.Trim() != String.Empty)
            {
                lBitDepth.Text = m.Groups[1].Value.Trim();
            }
            else
                lBitDepth.Text = "n/a";
            if (lBitDepth.Text == "32")
                lBitDepth.ForeColor = SystemColors.WindowText;
            else
                lBitDepth.ForeColor = Color.Red;


            m = Regex.Match(logcont, MatchlinkRegex, RegexOptions.Multiline);
            log.AppendText(String.Format("Matchlink: {0}", m.Groups[1].Value) + Environment.NewLine);


            bool gotscreen = false;
            try
            {
                if (Properties.Settings.Default.AequitasPath == String.Empty || !File.Exists(Properties.Settings.Default.AequitasPath))
                {
                    OpenFileDialog d = new OpenFileDialog();
                    d.CheckPathExists = true;
                    d.Title = "Please select your aequitas-executable";
                    d.Multiselect = false;
                    d.Filter = "ESL Aequitas (aequitas.exe)|aequitas.exe";
                    if (d.ShowDialog(this) == DialogResult.OK && File.Exists(d.FileName))
                    {
                        Properties.Settings.Default.AequitasPath = d.FileName;
                    }
                    else
                    {
                        AddFormattedString("ERROR:\tCan't check for manipulated files without aequitas", Color.Red, true);
                    }
                }
                if (File.Exists(Properties.Settings.Default.AequitasPath) && cbAutoCheckWithAequitas.Checked)
                    gotscreen = CheckFile(m.Groups[1].Value, aeqfile, Properties.Settings.Default.AequitasPath);
            }
            catch (Exception ex)
            {
                AddFormattedString("ERROR: " + ex.Message, Color.Red, true);
                Debug.WriteLine("ERROR: " + ex.Message + " @ " + Environment.NewLine + ex.StackTrace);
            }

            if (!gotscreen)
                AddFormattedString("ERROR:\t Could not check for manipulations, please check manually", Color.Red, false);

            CheckScreenshots(logcont, aeqfile);

            
            CheckConfigs(getConfigFromAeq(aeqfile), false, false);
            RefreshList();
        }

        private void AequitasChecker_DragDrop(object sender, DragEventArgs e)
        {
            Array a = (Array)e.Data.GetData(DataFormats.FileDrop);
            if (a != null)
            {
                for (int i = 0; i < a.Length; i++)
                {
                    string s = a.GetValue(i).ToString();
                    String ext = Path.GetExtension(s).ToLower();

                    if(ext == ".txt" || ext == ".cfg" || ext == ".rc")
                    {
                        StreamReader r = new StreamReader(s);
                        string content = r.ReadToEnd();
                        r.Close();
                        
                        CheckConfigs(content, false, false);
                        RefreshList();
                    }
                    else if(ext == ".zip")
                    {
                        PerformAequitasCheck(s);
                    }
                    else
                    {
                        MessageBox.Show("Fileformat '" + ext + "' not supported!");
                    }
                    /*	else if (ext == ".zip")
                        {
                            FormBrowseZip zip = new FormBrowseZip(this,s);
                            zip.Show();
                        }*/
                }

            }
        }

        private void AddFormattedString(string s)
        {
            AddFormattedString(s, log.ForeColor, false);
        }
        private void AddFormattedString(string s, Color color)
        {
            AddFormattedString(s, color, false);
        }

        private void AddFormattedString(string s, Color color, bool bold)
        {
            int start = log.Text.Length;
            log.AppendText(s + Environment.NewLine);
            //log.Text += s + Environment.NewLine;
            //log.SelectionStart = start;
            //log.SelectionLength = s.Length;
            log.Select(start, s.Length);
            
            log.SelectionColor = color;
            FontStyle style = FontStyle.Regular;

            if(bold)
                style = FontStyle.Bold;
            Font f = new Font(log.Font.FontFamily, log.Font.SizeInPoints, style);
            log.SelectionFont = f;
            //log.Select(start, s.Length);
            log.DeselectAll();
        }

        private void AequitasChecker_Load(object sender, EventArgs e)
        {
            lw.ListViewItemSorter = sort;
        }

        private void lw_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            ListView myListView = (ListView)sender;
            ListViewColumnSorter lvwColumnSorter = (ListViewColumnSorter)myListView.ListViewItemSorter;

            // Determine if clicked column is already the column that is being sorted.
            if (e.Column == lvwColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                if (lvwColumnSorter.Order == SortOrder.Ascending)
                {
                    lvwColumnSorter.Order = SortOrder.Descending;
                }
                else
                {
                    lvwColumnSorter.Order = SortOrder.Ascending;
                }
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                lvwColumnSorter.SortColumn = e.Column;
                lvwColumnSorter.Order = SortOrder.Ascending;
            }

            // Perform the sort with these new sort options.
            myListView.Sort();
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            //string aeqexe = 
            //CheckFile(@"http://www.esl.eu/de/cs/1on1/quickie_ladder/match/7671897/", @"C:\Downloads\aequitas_0_9c\archive\testdateien\cheater-aeq_test.zip");
            
        }

        private bool CheckFile(string matchlink, string file, string aeqpath)
        {
            CancelCheck = false;
            StatusProgress.Value = 0;
            StatusProgress.Maximum = 6;
            CancelProgress.Visible = true;
            /*if (AeqImg.Image != null)
            {
                try { AeqImg.Image.Dispose(); }
                catch{}
                
            }*/
            StatusText.Text = lang.AequitasStarting;
            Process proc = null;
            foreach(Process p in Process.GetProcessesByName("aequitas"))
            {
                proc = p;
            }
            if(proc != null)
            {
                if (MessageBox.Show("Aequitas may not already be running! Should I kill it now?", "Aequitas already running!", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    if (LucasCode.Tools.ESLHelpers.isAequitasMonitoring())
                    {
                        if (MessageBox.Show("AEQUITAS IS CURRENTLY MONITORING!" + Environment.NewLine + "ARE YOU SURE YOU WANT TO KILL THE PROCESS?", "WARNING!!!", MessageBoxButtons.YesNo) == DialogResult.Yes)
                            proc.Kill();
                    }
                    else
                        proc.Kill();
                }
                else
                    return false;
                //MessageBox.Show("Aequitas may not be running!");
                    
            }


            proc = new Process();
            //proc.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
            proc.StartInfo.FileName = aeqpath;
            proc.StartInfo.WorkingDirectory = Path.GetDirectoryName(aeqpath);
            //proc.StartInfo.CreateNoWindow = true;
            //proc.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
            proc.Start();
            

            bool success = false;
            //bool aborted = false;

            //try
            //{
            #region Check for manipulated files
            StatusText.Text = lang.AequitasInitializing;
            Application.DoEvents();
            //ManagedWinapi.Windows.SystemWindow aeqwin = new SystemWindow(User32.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "ESL Aequitas - Steam Version *BETA*", "ThunderRT6FormDC"));
            success = false;
            SystemWindow aeqwin = null;
            SystemWindow[] controls = null;
            while (!success && !CancelCheck)
            {
                IntPtr res1 = IntPtr.Zero;
                do
                                {
                SystemWindow[] ToplevelWindows = SystemWindow.AllToplevelWindows;
                foreach (SystemWindow w in ToplevelWindows)
                {
                    if (success || CancelCheck)
                        break;
                    if (w.Title.StartsWith("ESL Aequitas") && w.ClassName == "ThunderRT6FormDC" && w.Visible)
                    {
                        Thread.Sleep(500);
                        controls = w.AllChildWindows;
                        foreach (SystemWindow w2 in controls)
                        {
                            //Debug.WriteLine("found '" + w2.Title + "' (title '" + w2.ClassName + "')");
                            if (w2.ClassName == "ThunderRT6TextBox" && w2.Visible)
                            {
                                StringBuilder b = new StringBuilder(255);
                                string content = string.Empty;
                                HandleRef href = new HandleRef(w2, w2.HWnd);
                                
                                System.Text.UnicodeEncoding u = new System.Text.UnicodeEncoding();
                                //IntPtr strMem = Marshal.AllocCoTaskMem(u.GetByteCount(matchlink));
                                IntPtr strMem = Marshal.StringToCoTaskMemAuto(matchlink);
                                //Marshal.Copy(u.GetBytes(matchlink), 0, strMem, u.GetByteCount(matchlink));
                               
                                    //Marshal.
                                    //Thread.Sleep(200);
                                    res1 = User32.SendMessage(href, User32.WM_SETTEXT, IntPtr.Zero, strMem);
                                    //Thread.Sleep(200);
                                    //IntPtr res2 = User32.SendMessage(href, User32.WM_GETTEXT, new IntPtr(b.Capacity), b);
                                    Application.DoEvents();
                                
                                //Thread.Sleep(600);
                                
                                //Thread.Sleep(200);
                                /*SystemAccessibleObject textbox = SystemAccessibleObject.FromWindow(w2, AccessibleObjectID.OBJID_WINDOW);
                                foreach (SystemAccessibleObject o in textbox.Children)
                                    if ((AccessibleRole)o.Role == AccessibleRole.Text)
                                    {
                                        //o.DoDefaultAction();
                                        //o.DoDefaultAction();
                                        success = true;
                                        //Thread.Sleep(100);
                                        //proc.WaitForInputIdle();
                                        //Thread.Sleep(100);
                                        //Thread.Sleep(500);
                                        break;
                                    }
                                break;*/
                                //Thread.Sleep(100);
                                //proc.WaitForInputIdle();
                                //Thread.Sleep(100);
                                //Thread.Sleep(500);
                                aeqwin = new SystemWindow(w.HWnd);
                                success = true;
                                break;
                            }
                        }
                    }
                }
            } while (res1 == IntPtr.Zero && !CancelCheck);
            success = true;
                //this.Activate();
                //this.BringToFront();
                Application.DoEvents();
            }
            if (CancelCheck)
                return false;
            this.Activate();
            this.BringToFront();
            StatusProgress.Value++;
            StatusText.Text = lang.AequitasSetupMatchlink;
            Application.DoEvents();

            
            success = false;
            while (!success && !CancelCheck)
            {
                SystemWindow[] ToplevelWindows = SystemWindow.AllToplevelWindows;
                foreach (SystemWindow w in ToplevelWindows)
                {
                    if (success || CancelCheck)
                        break;
                    if (w.Title.StartsWith("ESL Aequitas") && w.ClassName == "ThunderRT6FormDC" && w.Visible)
                    {
                        controls = w.AllChildWindows;
                        foreach (SystemWindow w2 in controls)
                        {
                            //Debug.WriteLine("found '" + w2.Title + "' (title '" + w2.ClassName + "')");
                            if (w2.Title == "Check File")
                            {
                                //Debug.WriteLine("FOUND CHECK-BUTTON!");
                                SystemAccessibleObject stopmon = SystemAccessibleObject.FromWindow(w2, AccessibleObjectID.OBJID_WINDOW);
                                foreach (SystemAccessibleObject o in stopmon.Children)
                                    if (o.Name == "Check File")
                                    {
                                        o.DoDefaultAction();
                                        o.DoDefaultAction();
                                        success = true;
                                        //Thread.Sleep(100);
                                        //proc.WaitForInputIdle();
                                        //Thread.Sleep(100);
                                        //Thread.Sleep(500);
                                        break;
                                    }
                                break;
                            }
                        }
                    }
                }
                Application.DoEvents();
            }
            if (CancelCheck)
                return false;

            StatusProgress.Value++;
            //StatusText.Text = "Confirming matchlink";
            Application.DoEvents();
            success = false;
            while (!success && !CancelCheck)
            {
                SystemWindow[] ToplevelWindows = SystemWindow.AllToplevelWindows;
                foreach (SystemWindow w in ToplevelWindows)
                {
                    if (success || CancelCheck)
                        break;
                    if (w.Title == "aequitas" && (w.ExtendedStyle & WindowExStyleFlags.DLGMODALFRAME) == WindowExStyleFlags.DLGMODALFRAME)
                    {
                        foreach (SystemWindow w2 in w.AllChildWindows)
                        {
                            if (w2.DialogID == 6)
                            {
                                SystemAccessibleObject yesbutton = SystemAccessibleObject.FromWindow(w2, AccessibleObjectID.OBJID_WINDOW);
                                foreach (SystemAccessibleObject o in yesbutton.Children)
                                    if (o.RoleIndex == 43)
                                    {
                                        o.DoDefaultAction();
                                        o.DoDefaultAction();
                                        Debug.WriteLine("Pressed Button!!1111");
                                        success = true;
                                        //Thread.Sleep(1000);
                                        //proc.WaitForInputIdle();
                                        //Thread.Sleep(1000);
                                        //Thread.Sleep(500);
                                        break;
                                    }
                            }
                        }


                    }
                }
                Application.DoEvents();
            }
            if (CancelCheck)
                return false;
            Debug.WriteLine("INFO: searching for editbox");

            StatusProgress.Value++;
            StatusText.Text = lang.AequitasSelectFile;
            Application.DoEvents();
            success = false;
            bool linkentered = false;
            while (!success && !CancelCheck)
            {
                SystemWindow[] ToplevelWindows = SystemWindow.AllToplevelWindows;
                foreach (SystemWindow w in ToplevelWindows)
                {
                    if (success || CancelCheck)
                        break;
                    try
                    {
                        if (w.ClassName == "#32770" && w.Process.MainModule.ModuleName == "aequitas.exe" && w.Visible)
                        {
                            Debug.WriteLine("INFO: found open file dialog");
                            foreach (SystemWindow w2 in w.AllChildWindows)
                            {
                                /* differs on XP 32 and 64 bit, dunno why */
                                if ((w2.DialogID == 1148 || w2.ClassName == "Edit") && !linkentered && w.Visible)
                                {
                                    HandleRef href = new HandleRef(w2, w2.HWnd);
                                    Debug.WriteLine("INFO: Found editbox!");
                                    //Thread.Sleep(300);
                                    IntPtr strMem = Marshal.StringToCoTaskMemAuto(file);
                                    IntPtr res = User32.SendMessage(href, User32.WM_SETTEXT, IntPtr.Zero, strMem);
                                    //if (res != new IntPtr(1)) res = User32.SendMessage(href, User32.WM_SETTEXT, IntPtr.Zero, file);
                                    //if (res != new IntPtr(1)) res = User32.SendMessage(href, User32.WM_SETTEXT, IntPtr.Zero, file);
                                    Debug.WriteLine(String.Format("WM_SETTEXT returned '{0}')", res));
                                    if (res.ToInt64() == 1)
                                    {
                                        linkentered = true;
                                        Thread.Sleep(300);
                                    }
                                    //
                                    //proc.WaitForInputIdle();
                                }
                                else if (w2.DialogID == 1 && linkentered)
                                {
                                    //StringBuilder b = new StringBuilder(256);
                                    /*String str = new String('\0', 256);
                                    User32.SendMessage(w2.HWnd, User32.WM_GETTEXT, IntPtr.Zero, ref str);

                                    if (str == file)
                                        linkentered = true;
                                    else
                                    {
                                        Debug.WriteLine(String.Format("Filename could not be set! (was set to '{0}' instead of '{1}')", str, file));
                                        linkentered = false;
                                    }*/
                                    Debug.WriteLine("INFO: Found OK-Button!");
                                    SystemAccessibleObject okbutton = SystemAccessibleObject.FromWindow(w2, AccessibleObjectID.OBJID_WINDOW);
                                    foreach (SystemAccessibleObject o in okbutton.Children)
                                        if (o.RoleIndex == 43)
                                        {

                                            //o.Value = "TESTESTETSTST!";
                                            o.DoDefaultAction();
                                            o.DoDefaultAction();
                                            //o.DoDefaultAction();
                                            //o.DoDefaultAction();
                                            //Thread.Sleep(1000);
                                            //Debug.WriteLine("WROTE TEXT!!!!!!1111");
                                            //proc.WaitForInputIdle();
                                            //Thread.Sleep(3000);
                                            success = true;
                                            //Thread.Sleep(500);
                                            break;
                                        }
                                }

                            }
                            break;

                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("ERROR: " + ex.Message + " @ " + Environment.NewLine + ex.StackTrace);
                    }
                }
                Application.DoEvents();
            }
            if (CancelCheck)
                return false;
            Debug.WriteLine("INFO: finished searching for editbox");

            //#32770
            StatusProgress.Value++;
            StatusText.Text = lang.AequitasWaitForInfodialog;
            Application.DoEvents();
            IntPtr WinHandle = IntPtr.Zero;
            success = false;
            while (!success && !CancelCheck)
            {
                SystemWindow[] ToplevelWindows = SystemWindow.AllToplevelWindows;
                foreach (SystemWindow w in ToplevelWindows)
                {
                    if (success || CancelCheck)
                        break;
                    /*close annoying dialog if any*/
                    if ((w.Title == "ESL Aequitas File Check" || w.Title == "ESL Aequitas - File Check") && (w.ExtendedStyle & WindowExStyleFlags.DLGMODALFRAME) == WindowExStyleFlags.DLGMODALFRAME)
                    {
                        foreach (SystemWindow w2 in w.AllChildWindows)
                        {
                            if (w2.DialogID == 2)
                            {
                                SystemAccessibleObject okbutton = SystemAccessibleObject.FromWindow(w2, AccessibleObjectID.OBJID_WINDOW);
                                foreach (SystemAccessibleObject o in okbutton.Children)
                                    if (o.RoleIndex == 43)
                                    {
                                        o.DoDefaultAction();
                                        o.DoDefaultAction();
                                        //Debug.WriteLine("Pressed Button!!1111");
                                        //Thread.Sleep(1000);
                                        //proc.WaitForInputIdle();
                                        //Thread.Sleep(3000);
                                        //Thread.Sleep(500);
                                        break;
                                    }
                            }
                        }
                    }
                    else if ((w.Title == "ESL Aequitas File Check" || w.Title == "ESL Aequitas - File Check") && w.ClassName == "ThunderRT6FormDC" && w.Visible)
                    {
                        WinHandle = w.HWnd;
                        success = true;
                        break;
                    }
                }
                Application.DoEvents();
            }
            if (CancelCheck)
                return false;
            StatusProgress.Value++;
            StatusText.Text = lang.AequitasRetrieveInfo;
            Application.DoEvents();


                //IntPtr DC = User32.GetDC(WinHandle);
                //Graphics g = Graphics.FromHwnd(WinHandle);
                //Graphics g2 = Graphics.FromHwnd(AeqImg.Handle);

                //Thread.Sleep(1000);
                //this.Opacity = 0.99;
                //Thread.Sleep(2000);
                for (int j=0; j<20 && !CancelCheck; j++)
                {
                    Thread.Sleep(100);
                    Application.DoEvents();
                }
                if (CancelCheck)
                    return false;
                IntPtr handle = WinHandle;
                //this.Hide();
                //User32.BringWindowToTop(Handle);
                for (int j=0; j < 10 && !CancelCheck; j++)
                {
                    Thread.Sleep(100);
                    Application.DoEvents();
                }
                if (CancelCheck)
                    return false;
                IntPtr hdcSrc = User32.GetWindowDC(handle);
                LucasCode.Win32.RECT windowRect = new LucasCode.Win32.RECT();
                User32.GetWindowRect(handle, out windowRect);
                int width = windowRect.Width;
                int height = windowRect.Height;
                // create a device context we can copy to
                IntPtr hdcDest = Gdi32.CreateCompatibleDC(hdcSrc);
                // create a bitmap we can copy it to,
                // using GetDeviceCaps to get the width/height
                IntPtr hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, width, height);
                // select the bitmap object
                IntPtr hOld = Gdi32.SelectObject(hdcDest, hBitmap);
                // bitblt over
                //Gdi32.BitBlt(hdcDest, 0, 0, 135, 60, hdcSrc, 10, 38, Gdi32.TernaryRasterOperations.SRCCOPY);
                User32.PrintWindow(handle, hdcDest, 0x1);
                // restore selection
                Gdi32.SelectObject(hdcDest, hOld);
                // clean up
                Gdi32.DeleteDC(hdcDest);
                User32.ReleaseDC(handle, hdcSrc);
                // get a .NET image object for it
                Bitmap imgtmp = Image.FromHbitmap(hBitmap);
#if DEBUG
                imgtmp.Save("aeqcheck.png");
#endif
                int x = 11, y = 36;
                /* Add side border thickness */
                x +=  SystemInformation.Border3DSize.Width;
                /* Add title bar and top border thickness */
                y += SystemInformation.CaptionHeight + SystemInformation.Border3DSize.Width;
                Bitmap img = imgtmp.Clone(new Rectangle(x, y, 150, 50), imgtmp.PixelFormat);
                //Bitmap img = imgtmp.Clone(new Rectangle(0, 40, 150, 50), imgtmp.PixelFormat);
                // free up the Bitmap object
                Gdi32.DeleteObject(hBitmap);
                AeqImg.Image = img;
                //this.Show();
                //this.Opacity = 1;
                //this.Activate();
                //this.Focus();
                //this.BringToFront();

                
                StatusProgress.Value++;
                StatusText.Text = "Done checking for manipulated files.";
                Application.DoEvents();
#if !DEBUG
                if (img != null)
                    proc.Kill();
#endif
                CancelProgress.Visible = false;
                return (img != null);
            #endregion
            }

        private void bShowNext_Click(object sender, EventArgs e)
        {
            if (CurrentResult != null)
            {
                if (CurrentResult.BackColor == Color.Red)
                    CurrentResult.ImageIndex = 1;
                else if (CurrentResult.BackColor == Color.DarkOrange)
                    CurrentResult.ImageIndex = 2;
                else
                    CurrentResult.ImageIndex = 0;
            }
            if ((CurrentResult == null || !lw.Items.Contains(CurrentResult)) && lw.Items.Count > 0)
                CurrentResult = lw.TopItem;
            else if (lw.Items.Count <= 0)
                return;
            for (int i = CurrentResult.Index+1; i < lw.Items.Count; i++)
            {
                if(lw.Items[i].BackColor != lw.BackColor)
                {
                    lw.Items[i].EnsureVisible();
                    CurrentResult = lw.Items[i];
                    //lw.Items[i].Selected = true;
                    break;
                }
            }
            if (CurrentResult != null)
                CurrentResult.ImageIndex = 3;
        }

        private void bShowPrevious_Click(object sender, EventArgs e)
        {
            if (CurrentResult != null)
            {
                if (CurrentResult.BackColor == Color.Red)
                    CurrentResult.ImageIndex = 1;
                else if (CurrentResult.BackColor == Color.DarkOrange)
                    CurrentResult.ImageIndex = 2;
                else
                    CurrentResult.ImageIndex = 0;
            }
            if ((CurrentResult == null || !lw.Items.Contains(CurrentResult)) && lw.Items.Count > 0)
                CurrentResult = lw.TopItem;
            else if (lw.Items.Count <= 0)
                return;
            for (int i = CurrentResult.Index - 1; i > 0; i--)
            {
                if (lw.Items[i].BackColor != lw.BackColor)
                {
                    lw.Items[i].EnsureVisible();
                    CurrentResult = lw.Items[i];
                    //lw.Items[i].Selected = true;
                    break;
                }
            }
            if (CurrentResult != null)
                CurrentResult.ImageIndex = 3;
        }

        private void bBrowse_Click(object sender, EventArgs e)
        {
            if(Properties.Settings.Default.LastCheckFolder != String.Empty)
                AeqBrowser.InitialDirectory = Properties.Settings.Default.LastCheckFolder;
            if (AeqBrowser.ShowDialog() == DialogResult.OK)
            {
                Properties.Settings.Default.LastCheckFolder = Path.GetDirectoryName(AeqBrowser.FileName);
                PerformAequitasCheck(AeqBrowser.FileName);
            }
        }

        private void tSearchText_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.F3)
                bSearch.PerformClick();
        }

        private void bSearch_Click(object sender, EventArgs e)
        {
            int i=0;
            if (CurrentResult != null)
            {
                i = CurrentResult.Index + 1;
                if (CurrentResult.BackColor == Color.Red)
                    CurrentResult.ImageIndex = 1;
                else if (CurrentResult.BackColor == Color.DarkOrange)
                    CurrentResult.ImageIndex = 2;
                else
                    CurrentResult.ImageIndex = 0;
            }
            if ((CurrentResult == null || !lw.Items.Contains(CurrentResult)) && lw.Items.Count > 0)
            {
                CurrentResult = lw.TopItem;
                i = lw.TopItem.Index;
            }
            else if (lw.Items.Count <= 0)
                return;
            
            CurrentResult = null;
            for ( ; i < lw.Items.Count; i++)
            {
                if (lw.Items[i].Text.Contains(tSearchText.Text) || lw.Items[i].SubItems[1].Text.Contains(tSearchText.Text))
                {
                    lw.Items[i].EnsureVisible();
                    CurrentResult = lw.Items[i];
                    //lw.Items[i].Selected = true;
                    break;
                }
            }


            if (CurrentResult != null)
                CurrentResult.ImageIndex = 3;
            else
                if(lw.Items.Count > 0)
                    CurrentResult = lw.Items[0];
        }

        private void AequitasChecker_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F3)
                bSearch.PerformClick();
            //MessageBox.Show(e.KeyCode.ToString());
        }

        private void CancelProgress_Click(object sender, EventArgs e)
        {
            CancelCheck = true;
        }

        private void lw_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F3)
                bSearch.PerformClick();
        }

        static string ReplaceComments(Match m)
        {
            string x = string.Empty;
            if (m.Length > 1)
                x += new String(' ', m.Length - 1);
            x += '\n';
            return x;
        }
        private void InitDB()
        {
            if (m_Database == null)
            {
                m_Database = new SQLiteConnection("Data Source=" + Path.GetTempFileName() + ";Version=3;New=True;");
                m_Database.Open();
                SQLiteCommand cmd = m_Database.CreateCommand();
                cmd.CommandText = "create table cvars (column1 int, column2 char(1), etc);";

            }
            
        }
        SQLiteConnection m_Database;

        private LegalityLevel CheckConfigExpression(string expression, string cfg, int lineoffset, ConfigKeyValue parent)
        {
            int lastline = lineoffset, lastindex = 0;
            if (parent == null)
            {
                lastline--;
            }
            ConfigKeyValue newparent = null;
            if(expression == String.Empty)
                return LegalityLevel.Legal;
            string oldexpr = expression;
            expression = Regex.Replace(expression, "//.*\r*\n", new MatchEvaluator(ReplaceComments), RegexOptions.Multiline);
            LegalityLevel tmp = LegalityLevel.Legal;

            bool braceopen = false;
            //int subexpressioncount = 0;
            
            for (int i = 0; i < expression.Length; i++)
            {
                if (expression[i] == '\n')
                    braceopen = false;
                if (expression[i] == '\"')
                    braceopen = !braceopen;
                if (expression[i] == ';' && !braceopen)
                {
                    //subexpressioncount++;
                    expression = expression.Remove(i, 1);
                    expression = expression.Insert(i, "\n");
                }
            }

            //string ExpressionRegex = @"^[\ \t]*?(\S+?)[\ \t]+?""{0,1}([^""\n]+?)""{0,1}\s+?""{0,1}([^""]*?)""{0,1}\s*\r*$";
            //string ExpressionRegex = @"^[\ \t]*?([a-zA-Z\d_]+?)[\ \t]+""{0,1}([^""\r\n(?://)]+?)""{0,1}\s+?""{0,1}([^""(?://)]*?)""{0,1}[\ \t]*\r{0,1}(?://.*?)*$";

            string ExpressionRegex = @"^[\ \t]*
                                        ([a-zA-Z\d_]+)
                                        [\ \t]+
                                        ""{0,1}([a-zA-Z\d_\+-@]+)""{0,1}
                                        [\ \t]*
                                        ""{0,1}([^\r\n\""]*)";
            MatchCollection matches = Regex.Matches(expression, ExpressionRegex, RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);
            foreach(Match m in matches)
            {

                lastline = GetLineFromIndex(oldexpr, m.Index, lastindex) + lastline;
                lastindex = m.Index;
                try
                {
                    StatusProgress.Value = lastline;
                }
                catch{}
                Application.DoEvents();
                //AddFormattedString(String.Format("Command: {0}, Value: {1}, Argument 3: {2}", m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value));
                
               
                switch (m.Groups[1].Value)
                {
                    case "bind":
                        newparent = new BindingSetting(m.Groups[2].Value, m.Groups[3].Value, cfg, lastline);
                        settings.Add(newparent);
                        if (parent != null)
                            parent.Legality |= settings.CheckSetting(newparent);
                        /*AddFormattedString(String.Format("Binding: {0} -> {1}", m.Groups[2].Value, m.Groups[3].Value));*/
                        break;
                    case "alias":
                        if (m.Groups[3].Value != string.Empty)
                        {
                            newparent = new AliasSetting(m.Groups[2].Value, m.Groups[3].Value, cfg, lastline);
                            settings.Add(newparent);
                            if (parent != null)
                                parent.Legality |= settings.CheckSetting(newparent);
                        }
                        break;
                    case "exec":
                        break;
                    case "echo":
                        break;
                    default:
                        if (m.Groups[3].Value == string.Empty)
                        {
                            newparent = new CvarSetting(m.Groups[1].Value, m.Groups[2].Value, cfg, lastline);
                            settings.Add(newparent);
                            if (parent != null)
                                parent.Legality |= settings.CheckSetting(newparent);
                        }
                        break;
                }
            
                
                if (m.Groups[3].Value.Contains(" "))
                {
                    tmp |= CheckConfigExpression(m.Groups[3].Value, cfg, lastline, newparent);
                }
            }
            if (newparent != null)
                return tmp | newparent.Legality;
            else
                return tmp;
        }
        private void RefreshList()
        {
            lw.Items.Clear();
            lw.BeginUpdate();
            tSearchText.AutoCompleteCustomSource.Clear();
            StatusText.Text = lang.FillList;
            StatusProgress.Value = 0;
            StatusProgress.Maximum = settings.Count;
            foreach(ConfigKeyValue v in settings)
            {
                if (cbOnlyShowAnomalies.Checked && v.Legality == LegalityLevel.Legal)
                    continue;
                tSearchText.AutoCompleteCustomSource.Add(v.Key);
                ListViewItem i = new ListViewItem();
                i.Text = v.Key;
                i.ImageIndex = 0;
                i.SubItems.Add(v.Value);
                i.SubItems.Add(v.Line.ToString());
                i.SubItems.Add(v.Config);
                if((v.Legality & LegalityLevel.Illegal) > 0)
                {
                    i.ForeColor = Color.White;
                    i.BackColor = Color.Red;
                    i.ImageIndex = 1;
                }
                else if ((v.Legality & LegalityLevel.Suspicious) > 0)
                {
                    //i.ForeColor = Color.White;
                    i.BackColor = Color.DarkOrange;
                    i.ImageIndex = 2;
                }
                switch(v.ValueType)
                {
                    case ConfigKeyValueType.Cvar:
                        i.Group = lw.Groups["Settings"];
                        if (!((CvarSetting)v).isString)
                            i.SubItems[1].Text = ((CvarSetting)v).NumVal.ToString();
                        break;
                    case ConfigKeyValueType.Binding:
                        i.Text = i.Text.ToUpper();
                        i.Group = lw.Groups["Bindings"];
                        break;
                    case ConfigKeyValueType.Alias:
                        i.Group = lw.Groups["Aliases"];
                        break;
                }
                lw.Items.Add(i);
                try
                {
                    StatusProgress.Value++;
                }catch{}
                Application.DoEvents();
            }
            StatusProgress.Value = StatusProgress.Maximum;
            StatusText.Text = lang.ValueListDoubleclick;
            lw.EndUpdate();
        }

        private void cbOnlyShowAnomalies_CheckedChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.InspectorOnlyAnomalies = cbAutoCheckWithAequitas.Checked;
            RefreshList();
        }

        private void lw_DoubleClick(object sender, EventArgs e)
        {
            foreach(ListViewItem i in lw.SelectedItems)
            {
                configviewer.Show(config, Convert.ToInt32(i.SubItems[2].Text), settings.anomalies);
            }
        }

        private void cbAutoCheckWithAequitas_CheckedChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.InspectorAutoCheckForManipulation = cbAutoCheckWithAequitas.Checked;
        }

        private void bConfigViewer_Click(object sender, EventArgs e)
        {
            configviewer.Show(config, 1, settings.anomalies);
        }

        private void AequitasChecker_FormClosing(object sender, FormClosingEventArgs e)
        {
            CancelCheck = true;
        }

        private void AequitasChecker_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.Dispose();
        }
    }
    public enum ConfigSettingType
    {
        StringValue,
        NumericValue,
        OtherValue
    }

    public class ScreenshotInfo
    {
        public ScreenshotInfo(string name, DateTime lastwritedate)
        {
            Name = name;
            LastWriteDate = lastwritedate;
        }
        public DateTime LastWriteDate;
        public string Name;
    };

    public class ScreenshotInfoCollection : CollectionBase
    {
        public int Add(ScreenshotInfo item)
        {
            return List.Add(item);
        }
        public void Insert(int index, ScreenshotInfo item)
        {
            List.Insert(index, item);
        }
        public void Remove(ScreenshotInfo item)
        {
            List.Remove(item);
        }
        public bool Contains(ScreenshotInfo item)
        {
            return List.Contains(item);
        }
        public int IndexOf(ScreenshotInfo item)
        {
            return List.IndexOf(item);
        }
        public void CopyTo(ScreenshotInfo[] array, int index)
        {
            List.CopyTo(array, index);
        }
        public ScreenshotInfo this[int index]
        {
            get { return (ScreenshotInfo)List[index]; }
            set { List[index] = value; }
        }
        public ScreenshotInfo this[string name]
        {
            get
            {
                foreach (ScreenshotInfo c in List)
                    if (c.Name.ToLower() == name.ToLower())
                        return c;
                return null;
            }
        }
    }


#region ForcedCvar
    public class ForcedCvar
    {
        public ForcedCvar(string Name, double ForcedValue)
        {
            this.Name = Name;
            this.MinVal = ForcedValue;
            this.MaxVal = ForcedValue;
        }
        public ForcedCvar(string Name, double MinVal, double MaxVal)
        {
            this.Name = Name;
            this.MinVal = MinVal;
            this.MaxVal = MaxVal;
        }
        public string Name;
        public double MinVal = double.MinValue;
        public double MaxVal = double.MaxValue;
    };

    public class ForcedCvarCollection : CollectionBase
    {
        public int Add(ForcedCvar item)
        {
            return List.Add(item);
        }
        public void Insert(int index, ForcedCvar item)
        {
            List.Insert(index, item);
        }
        public void Remove(ForcedCvar item)
        {
            List.Remove(item);
        }
        public bool Contains(ForcedCvar item)
        {
            return List.Contains(item);
        }
        public int IndexOf(ForcedCvar item)
        {
            return List.IndexOf(item);
        }
        public void CopyTo(ForcedCvar[] array, int index)
        {
            List.CopyTo(array, index);
        }
        public ForcedCvar this[int index]
        {
            get { return (ForcedCvar)List[index]; }
            set { List[index] = value; }
        }
        public ForcedCvar this[string name]
        {
            get {
                foreach(ForcedCvar c in List)
                    if (c.Name.ToLower() == name.ToLower())
                        return c;
                return null;
            }
        }
    }
#endregion ForcedCvar

    public class AliasSetting : ConfigKeyValue
    {
        public AliasSetting(string Alias, string Action, string Config, int Line)
            : base(Alias, Action, Config, Line)
        {
            this.ValueType = ConfigKeyValueType.Alias;
        }
    };

    public class BindingSetting : ConfigKeyValue
    {
        public BindingSetting(string Key, string Action, string Config, int Line)
            : base(Key, Action, Config, Line)
        {
            this.ValueType = ConfigKeyValueType.Binding;
        }
    };

    public class CvarSetting : ConfigKeyValue
    {
        /*public ConfigSetting(string name, string val, string config)
        {
            Name = name;
            Value = val;
            Config = config;
            NumVal = Convert.ToDouble(val, System.Globalization.NumberFormatInfo.InvariantInfo);
        }*/
        public CvarSetting(string Name, string Value, string Config, int Line) : base(Name,Value,Config,Line)
        {
            try
            {
                NumVal = Convert.ToDouble(Value, System.Globalization.NumberFormatInfo.InvariantInfo);
            }catch{
                isString = true;
            }
            this.ValueType = ConfigKeyValueType.Cvar;
        }
        public bool IsLegal(ForcedCvarCollection rules)
        {
            ForcedCvar rule = rules[this.Key];
            if (rule != null && (NumVal < rule.MinVal | NumVal > rule.MaxVal))
            {
                RectrictedBy = rule;
                return false;
            }
            return true;
        }
        public ForcedCvar RectrictedBy;
        public double NumVal;
        public bool isString = false;
    };


    public enum ConfigKeyValueType
    {
        Alias,
        Binding,
        Cvar
    }

    [Flags]
    public enum LegalityLevel :uint
    {
        Legal =         0x00,
        Illegal =       0x01,
        Suspicious =    0x02
    }

    public class ConfigKeyValue
    {
        public ConfigKeyValue(string key, string action, string config, int line)
        {
            while(key.StartsWith("\""))
                key = key.Substring(1,key.Length-1);
            while(key.EndsWith("\""))
                key = key.Substring(0,key.Length-1);
            Key = key.Trim().ToLower();
            Value = action.Trim().ToLower();
            Config = config.Trim();
            Line = line;
        }

        public string Key;
        public string Value;
        public string Config;
        public int Line;
        public ConfigKeyValueType ValueType;
        public LegalityLevel Legality;
        //public bool Duplicate = false;
    };

    public class KeyValueCollection : CollectionBase
    {
        public KeyValueCollection()
        {
            Rules.Add(new ForcedCvar("cl_movespeedkey", 0.52));
            Rules.Add(new ForcedCvar("cl_pitchspeed", 225));
            Rules.Add(new ForcedCvar("d_spriteskip", 0));
            Rules.Add(new ForcedCvar("gl_max_size", 128, double.MaxValue));
            Rules.Add(new ForcedCvar("gl_monolights", 0));
            Rules.Add(new ForcedCvar("gl_picmip", 0));
            Rules.Add(new ForcedCvar("gl_polyoffset", 0, 4));
            Rules.Add(new ForcedCvar("s_show", 0));

            Rules.Add(new ForcedCvar("s_a3d", 0));
            Rules.Add(new ForcedCvar("lightgamma", 2.5));
            Rules.Add(new ForcedCvar("texgamma", 2));

            Rules.Add(new ForcedCvar("cl_lw", 1));
            Rules.Add(new ForcedCvar("cl_lc", 1));
        }
        public ForcedCvarCollection Rules = new ForcedCvarCollection();
        //public KeyValueCollection anomalies = new KeyValueCollection();
        public List<ConfigKeyValue> anomalies = new List<ConfigKeyValue>();
        public int WrongSettings = 0;
        public int SuspiciousScripts = 0;
        public bool AllowDuplicates = false;

        public LegalityLevel CheckSetting(ConfigKeyValue item)
        {
            if (item.ValueType == ConfigKeyValueType.Cvar && !((CvarSetting)item).isString)
            {
                ForcedCvar rule = Rules[item.Key];
                if (rule != null && (((CvarSetting)item).NumVal < rule.MinVal | ((CvarSetting)item).NumVal > rule.MaxVal))
                {
                    return LegalityLevel.Illegal;
                }
            }
            else if (item.ValueType == ConfigKeyValueType.Binding)
            {
                if ((item.Key.Contains("mwheelup") || item.Key.Contains("mwheeldown")) && (item.Value.Contains("+duck") || item.Value.Contains("+jump")))
                {
                    return LegalityLevel.Illegal;
                }
            }
            else if (item.ValueType == ConfigKeyValueType.Alias)
            {
                if (Regex.Match(item.Key, "^@").Success)
                {
                    return LegalityLevel.Suspicious;
                }
                else if (Regex.Match(item.Value, @"(\+duck|\+jump|_special|@special)").Success)
                {
                    return LegalityLevel.Suspicious;
                }
            }
            return LegalityLevel.Legal;
        }

        public int Add(ConfigKeyValue item)
        {
            LegalityLevel tmp = CheckSetting(item);
            item.Legality |= tmp;
            if (AllowDuplicates)
            {
                if (tmp == LegalityLevel.Illegal)
                    WrongSettings++;
                else if(tmp == LegalityLevel.Suspicious)
                    SuspiciousScripts++;
                if (tmp > LegalityLevel.Legal)
                    anomalies.Add(item);
                return List.Add(item);
            }
            else
            {
                bool exists = false;
                foreach (ConfigKeyValue c in List)
                {
                    if (c.Key == item.Key && c.Value == item.Value)
                    {
                        exists = true;
                        break;
                    }
                }
                if (!exists)
                {
                    if (tmp == LegalityLevel.Illegal)
                        WrongSettings++;
                    else if (tmp == LegalityLevel.Suspicious)
                        SuspiciousScripts++;
                    if (tmp > LegalityLevel.Legal)
                        anomalies.Add(item);
                    return List.Add(item);
                }
                else
                    return -1;
            }
        }
        new public void Clear()
        {
            base.Clear();
            anomalies.Clear();
            WrongSettings = 0;
            SuspiciousScripts = 0;
        }
        public void Insert(int index, ConfigKeyValue item)
        {
            List.Insert(index, item);
        }
        public void Remove(ConfigKeyValue item)
        {
            List.Remove(item);
        }
        public bool Contains(ConfigKeyValue item)
        {
            return List.Contains(item);
        }
        public int IndexOf(ConfigKeyValue item)
        {
            return List.IndexOf(item);
        }
        public void CopyTo(ConfigKeyValue[] array, int index)
        {
            List.CopyTo(array, index);
        }
        public ConfigKeyValue this[int index]
        {
            get { return (ConfigKeyValue)List[index]; }
            set { List[index] = value; }
        }
        /*public ConfigBinding this[string name]
        {
            get
            {
                foreach (ConfigBinding c in List)
                    if (c.Name.ToLower() == name.ToLower())
                        return c;
                return null;
            }
            /*set {
                List[index] = value;
            }
        }*/
    }
    [ToolStripItemDesignerAvailability
   (ToolStripItemDesignerAvailability.All)]
    public class CheckBoxMenuStripItem : ToolStripControlHost
    {
        private CheckBox chk;
        public event EventHandler CheckedChanged;
        public CheckBoxMenuStripItem() : base(new CheckBox())
        {
            chk = (CheckBox)this.Control;
            chk.BackColor = Color.Transparent;
            chk.AutoSize = true;
            chk.Checked = true;
            chk.CheckedChanged += new EventHandler(chk_CheckedChanged);
            //chk.Doc
        }

        void chk_CheckedChanged(object sender, EventArgs e)
        {
            if (CheckedChanged != null)
                CheckedChanged(sender, e);
        }
        [DefaultValue(true)]
        public bool Checked
        {
            get { return chk.Checked; }
            set { chk.Checked = value; }
        }
    };
}